﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IceDog.WebApi.AnythingApi.CustomMiddlewares
{
    /// <summary>
    /// 
    /// </summary>
    public static class MiddlewareExtensions
    {
        /// <summary>
        /// 缓存swagger.json 文件
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseCacheSwaggerFileMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<CacheSwaggerFileMiddleware>();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class CacheSwaggerFileMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="next"></param>
        /// <param name="loggerFactory"></param>
        public CacheSwaggerFileMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.CreateLogger<CacheSwaggerFileMiddleware>();

        }

        /// <summary>
        /// 拦截返回的json文件，写入到生成文件，下次读取就直接读取生成好的文件
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            //允许请求多次读取
            context.Request.EnableBuffering();
            var req = context.Request;
            var resBody = context.Response.Body;
            try
            {
                if (!req.Path.Value.EndsWith("swagger.json"))
                {
                    await _next(context);
                    return;
                }
                var fileName = req.Path.Value.Replace("/", "-");
                var tempFolderPath = Path.Combine(AppContext.BaseDirectory, "temp-swagger");
                if (!Directory.Exists(tempFolderPath))
                {
                    Directory.CreateDirectory(tempFolderPath);
                }
                var filePath = Path.Combine(tempFolderPath, fileName);
                //替换掉原始的body流
                var fakeResBody = new MemoryStream();
                context.Response.Body = fakeResBody;
                //缓存文件存在则直接使用缓存文件返回
                if (File.Exists(filePath))
                {
                    using var cacheFileStream = File.OpenRead(filePath);
                    await cacheFileStream.CopyToAsync(resBody);
                    await cacheFileStream.FlushAsync();
                    cacheFileStream.Close();
                    return;
                }
                //不存在就交给后续的中间件执行
                await _next(context);
                //拦截后续中间件对路由的响应，并写入到缓存文件
                using var newCacheFileStream = File.OpenWrite(filePath);
                fakeResBody.Position = 0L;
                //接收的流数据拷贝到缓存文件流
                await fakeResBody.CopyToAsync(newCacheFileStream);
                await newCacheFileStream.FlushAsync();
                newCacheFileStream.Close();
                //流归位重读
                fakeResBody.Position = 0L;
                //接收的流数据拷贝到原始的响应流里面
                await fakeResBody.CopyToAsync(resBody);
                fakeResBody.Close();
            }
            catch (Exception ex)
            {
                _logger.LogError($" 缓存 swagger.json 发生错误: " + ex.ToString());
            }
            finally
            {
                await resBody.FlushAsync();
                context.Response.Body = resBody;
            }

            // 响应完成时存入缓存
            context.Response.OnCompleted(() =>
            {
                //_logger.LogDebug($"请求执行完成");
                return Task.CompletedTask;
            });

        }
    }
}
